package com.bmt.core;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import com.bmt.utils.String_Utils;
import com.bmt.utils.System_Utils;

public abstract class BaseDao extends JdbcDaoSupport {
	@Resource
	public void setDataSourcex(DataSource dataSource) {
		setJdbcTemplate(new JdbcTemplate(dataSource));
	}

	public Number saveAndReturnKey(ISaveable objForSave) {
		return saveAndReturnKey(objForSave, objForSave._getTableName(),
				objForSave._getKeyColumns());
	}

	public Number saveAndReturnKey(Object objForSave, String tableName,
			String... keyColumns) {
		SimpleJdbcInsert insertActor = getSimpleJdbcInsert();
		insertActor.setTableName(tableName);
		insertActor.usingGeneratedKeyColumns(keyColumns);
		Number newId = insertActor
				.executeAndReturnKey(new BeanPropertySqlParameterSource(
						objForSave));
		traceSql(insertActor.getInsertString());
		return newId;
	}

	public void save(ISaveable objForSave) {
		save(objForSave, objForSave._getTableName());
	}

	public void save(Object objForSave, String tableName) {
		SimpleJdbcInsert insertActor = getSimpleJdbcInsert();
		insertActor.setTableName(tableName);
		insertActor.execute(new BeanPropertySqlParameterSource(objForSave));
		traceSql(insertActor.getInsertString());
	}

	public Number saveAndReturnKey(String tableName,
			Map<String, Object> columnAndValue, String... keyColumns) {
		SimpleJdbcInsert insertActor = getSimpleJdbcInsert();
		insertActor.setTableName(tableName);
		insertActor.usingGeneratedKeyColumns(keyColumns);
		Number newId = insertActor.executeAndReturnKey(columnAndValue);
		traceSql(insertActor.getInsertString());
		return newId;
	}

	public SimpleJdbcInsert getSimpleJdbcInsert() {
		return new SimpleJdbcInsert(getJdbcTemplate());
	}

	public void traceSql(String sql) {
		System.out.println("JDBC:" + sql);
	}

	public <T extends ISaveable> PageListInfo<T> getPageListInfo(int pageNum,
			int pageSize) {
		List<T> dataList = getDataByPage((pageNum - 1) * pageSize, pageSize);
		PageListInfo<T> plInfo = new PageListInfo<T>();
		plInfo.setCurrPageNum(pageNum);
		plInfo.setDataList(dataList);
		plInfo.setPageSize(pageSize);
		int total = getDataTotal();
		plInfo.setDataTotalNum(total);

		return plInfo;
	}

	public <T extends ISaveable> PageListInfo<T> getPageListInfo(int pageNum) {
		return getPageListInfo(pageNum, System_Utils.PAGE_SIZE);
	}

	public abstract int getDataTotal();

	public abstract <T extends ISaveable> List<T> getDataByPage(int pageNum,
			int pageSize);

	public int update(ISaveable objForSave) throws IllegalArgumentException,
			IllegalAccessException {
		StringBuilder sqlBuilder = new StringBuilder("UPDATE ");
		StringBuilder sqlWhereBuilder = new StringBuilder(" Where ");
		sqlBuilder.append(objForSave._getTableName());
		sqlBuilder.append(" SET ");
		List<Object> sqlValList = new ArrayList<Object>();
		List<Object> whereValList = new ArrayList<Object>();
		boolean sql_first = true;
		boolean where_first = true;
		for (Field field : objForSave.getClass().getDeclaredFields()) {
			if (Modifier.isFinal(field.getModifiers())
					|| Modifier.isStatic(field.getModifiers()))
				continue;
			System.out.println(field.getName());
			field.setAccessible(true);
			if (String_Utils.inArray(objForSave._getKeyColumns(),
					field.getName())) {
				if (!where_first) {
					sqlWhereBuilder.append(" AND ");
				}
				where_first = false;
				sqlWhereBuilder.append(field.getName());
				sqlWhereBuilder.append("= ? ");
				whereValList.add(field.get(objForSave));
			} else {
				if (!sql_first) {
					sqlBuilder.append(",");
				}
				sql_first = false;
				// 要排除Key中的字段
				sqlBuilder.append(field.getName());
				sqlBuilder.append(" = ? ");
				sqlValList.add(field.get(objForSave));
			}
		}
		sqlBuilder.append(sqlWhereBuilder.toString());
		sqlValList.addAll(whereValList);
		return getJdbcTemplate().update(sqlBuilder.toString(),
				sqlValList.toArray());
	}

	public int delete(ISaveable objForSave) throws NoSuchFieldException,
			SecurityException, IllegalArgumentException, IllegalAccessException {
		StringBuilder sqlBuilder = new StringBuilder("DELETE FROM ");
		sqlBuilder.append(objForSave._getTableName());
		sqlBuilder.append(" WHERE ");
		boolean first = true;
		List<Object> whereValList = new ArrayList<Object>();
		for (String key : objForSave._getKeyColumns()) {
			if (first) {
				sqlBuilder.append(" WHERE ");
			} else {
				sqlBuilder.append(" AND ");
			}
			first = false;
			sqlBuilder.append(key);
			sqlBuilder.append("= ? ");
			Field field = objForSave.getClass().getDeclaredField(key);
			field.setAccessible(true);
			whereValList.add(field.get(objForSave));
		}
		return getJdbcTemplate().update(sqlBuilder.toString(),
				whereValList.toArray());
	}

	public int delete(String table, String keyField, String keyFieldValue) {
		String sql = "DELETE FROM " + table + " WHERE " + keyField
				+ "=:keyFieldValue";
		return getJdbcTemplate().update(sql,
				new MapSqlParameterSource("keyFieldValue", keyFieldValue));
	}
}
